package sasku.client.core.connection;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.util.HashSet;
import java.util.Set;

import org.apache.log4j.Logger;

import sasku.client.core.Environment;
import sasku.client.core.Main;
import sasku.client.core.Settings;
import sasku.client.core.message.Message;
import sasku.client.core.message.ServerMessage;
import sasku.client.core.message.listener.MessageListener;

public class ServerConnectionImpl implements ServerConnection {

	/** Logger */
	private static Logger log = Logger.getLogger(Main.class);

	private Socket socket = new Socket();
	private PrintWriter writer;
	private Set<MessageListener> listeners = new HashSet<MessageListener>();

	public boolean connect() {

		Settings settings = Settings.getInstance();

		if (log.isDebugEnabled()) {
			log.debug("Connecting to " + settings.getHosts() + ':' + settings.getPort());
		}

		InetSocketAddress address = new InetSocketAddress(settings.getHosts(), settings.getPort());
		if (address.isUnresolved()) {
			log.warn("Unable to resolv host [" + settings.getHosts() + ']');
			return false;
		}

		try {
			socket.connect(address);
			return true;
		} catch (IOException e) {
			log.warn("Failed to connect", e);
			return false;
		}
	}

	public void run() {
		BufferedReader reader;
		try {
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		} catch (IOException e) {
			throw new RuntimeException("Failed to get input stream", e);
		}
		
		try {
			String line;
			while ((line = reader.readLine()) != null) {
				log.debug("Server message: " + line);
				
				notifyListeners(new ServerMessage(line));
			}
		} catch (IOException e) {
			throw new RuntimeException("Failed to read message from server", e);
		}
	}

	public void addListener(MessageListener listener) {
		listeners.add(listener);
	}

	private void notifyListeners(ServerMessage message) {
		for (MessageListener listener : listeners) {
			listener.update(message, this);
		}
	}

	public void sendMessage(Message message) {
		writer.print(message.getMessage());
		writer.flush();
	}

	public void startConversation() {
		try {
			writer = new PrintWriter(socket.getOutputStream(), true);
		} catch (IOException e) {
			throw new RuntimeException("Failed to get output stream", e);
		}

		writer.print("VERSION ");
		writer.println(Environment.VERSION);
		writer.flush();

	}

}
